package com.dingreading.cloud.gateway.filters;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
import com.dingreading.cloud.common.util.IpUtil;
import com.dingreading.cloud.gateway.entity.RequestLog;
import com.dingreading.cloud.gateway.service.RequestLogService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/***
 * 全局过滤器
 */
@Component
public class LogFilter implements GlobalFilter, Ordered {
//    Logger log = LoggerFactory.getLogger(this.getClass());

    @Resource
    private RequestLogService requestLogService;

    public static LogFilter util;

    @PostConstruct
    public void init() {
        util = this;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 异步保存请求日志
        CompletableFuture.supplyAsync(() -> {
            saveLog(exchange);
            return "";
        }).exceptionally(ex -> {
            System.out.println("异步保存请求日志异常: " + ex.getMessage());
            return "";
        }).handle((result, ex) -> "");

//        log.info(exchange.getRequest().getPath().value());
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }

    /**
     * 保存请求日志
     */
    private void saveLog(ServerWebExchange exchange) {
        ServerHttpRequest request = exchange.getRequest();
        URI uri = request.getURI();
        String path = uri.getPath();
        if (path != null && (path.contains("/api-docs") || uri.getPath().contains("cdn/auth/check"))){
            return;
        }

        // 请求ip
        String ip = IpUtil.getIP(request);
        // 请求方法
        String methodName = request.getMethodValue();
        // 请求url
        String url = uri.getScheme() + "://" + uri.getAuthority() + path;
        // 从请求参数中获取 JSON
        String paramJson = queryParamsToJson(request.getQueryParams()); // 调用已修复的方法

        // 保存请求记录
        saveReqLog(ip, methodName, url, paramJson);
    }

    /**
     * 将body中的字符串格式化
     */
    private String postParamToJson(String cachedRequestBody) {
        if (cachedRequestBody == null || "".equals(cachedRequestBody.trim()))
            return "";

        JSONObject jsonObject = new JSONObject();
        //解析body中的参数
        String[] splitURL = cachedRequestBody.split("&");
        try {
            for (String param : splitURL) {
                if (param.indexOf("=") > 0) {
                    int index = param.indexOf("=");
                    String key = param.substring(0, index);
                    String value = param.substring(index + 1);
                    if (StringUtils.isNotBlank(value) && value.contains("%"))
                        // url编码与中文的互相转换
                        value = URLDecoder.decode(value, "UTF-8");
                    jsonObject.put(key, value);
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return jsonObject.toJSONString();
    }

    /**
     * 参数转json格式字符
     */
    private String queryParamsToJson(MultiValueMap<String, String> parameterMap) {
        if (!parameterMap.isEmpty()) {
            JSONObject jsonObject = new JSONObject();
            for (Map.Entry<String, List<String>> stringEntry : parameterMap.entrySet()) {
                String key = stringEntry.getKey();
                List<String> value = stringEntry.getValue();
                String valueStr = "";
                if (value != null && value.size() > 0) {
                    ArrayList<String> strings = Lists.newArrayList(value);
                    valueStr = StringUtils.strip(strings.toString(), "[]");
                }
                jsonObject.put(key, valueStr);
            }
            return jsonObject.toJSONString();
        }
        return "";
    }

    /**
     * 保存请求记录
     */
    private void saveReqLog(String ip, String methodName, String url, String paramJson) {
        RequestLog log = new RequestLog();
        log.setIp(ip);
        log.setMethod(methodName);
        log.setRequestUrl(url);
        log.setJsonRequest(paramJson);
        util.requestLogService.saveOrUpdate(log);
    }

}
